﻿using System;
using System.Collections.Generic;
using System.Text;

namespace MLForgeSharp.Models.SupervisedLearningModels.VectorMachine
{
    /// <summary>
    /// 支持向量机
    /// </summary>
    public class SVM
    {
        private double[] weights; // 权重向量
        private double bias; // 偏置项
        private double learningRate; // 学习率
        private double lambda; // 正则化参数
        private int maxIterations; // 最大迭代次数
        private KernelFunction kernel; // 核函数

        // 自定义核函数委托
        public delegate double KernelFunction(double[] x1, double[] x2);

        public SVM(double learningRate = 0.01, double lambda = 0.01, int maxIterations = 1000, KernelFunction kernel = null)
        {
            this.learningRate = learningRate;
            this.lambda = lambda;
            this.maxIterations = maxIterations;
            this.kernel = kernel ?? LinearKernel; // 默认使用线性核
        }

        // 线性核函数
        private double LinearKernel(double[] x1, double[] x2)
        {
            double sum = 0.0;
            for (int i = 0; i < x1.Length; i++)
            {
                sum += x1[i] * x2[i];
            }
            return sum;
        }

        // 多项式核函数
        private double PolynomialKernel(double[] x1, double[] x2, double gamma = 1.0, double coef0 = 1.0, int degree = 3)
        {
            double sum = 0.0;
            for (int i = 0; i < x1.Length; i++)
            {
                sum += x1[i] * x2[i];
            }
            return Math.Pow(gamma * sum + coef0, degree);
        }

        // 高斯核函数（RBF 核）
        private double GaussianKernel(double[] x1, double[] x2, double gamma = 1.0)
        {
            double sum = 0.0;
            for (int i = 0; i < x1.Length; i++)
            {
                sum += Math.Pow(x1[i] - x2[i], 2);
            }
            return Math.Exp(-gamma * sum);
        }

        // Sigmoid 核函数
        private double SigmoidKernel(double[] x1, double[] x2, double gamma = 1.0, double coef0 = 1.0)
        {
            double sum = 0.0;
            for (int i = 0; i < x1.Length; i++)
            {
                sum += x1[i] * x2[i];
            }
            return Math.Tanh(gamma * sum + coef0);
        }

        // 训练模型
        public void Train(double[][] inputs, int[] targets)
        {
            int numSamples = inputs.Length;
            int numFeatures = inputs[0].Length;
            weights = new double[numFeatures];
            bias = 0.0;

            for (int iter = 0; iter < maxIterations; iter++)
            {
                for (int i = 0; i < numSamples; i++)
                {
                    double prediction = Predict(inputs[i]);
                    int target = targets[i];

                    if (target * prediction < 1) // 违反间隔条件
                    {
                        for (int j = 0; j < numFeatures; j++)
                        {
                            weights[j] -= learningRate * (lambda * weights[j] - target * inputs[i][j]);
                        }
                        bias -= learningRate * (-target);
                    }
                    else // 满足间隔条件
                    {
                        for (int j = 0; j < numFeatures; j++)
                        {
                            weights[j] -= learningRate * lambda * weights[j];
                        }
                    }
                }
            }
        }

        // 预测
        public int Predict(double[] inputs)
        {
            double sum = bias;
            for (int i = 0; i < inputs.Length; i++)
            {
                sum += weights[i] * inputs[i];
            }
            return sum >= 0 ? 1 : -1;
        }

        // 使用核函数进行预测
        public int PredictWithKernel(double[] inputs, double[][] supportVectors, int[] supportVectorLabels)
        {
            double sum = bias;
            for (int i = 0; i < supportVectors.Length; i++)
            {
                sum += supportVectorLabels[i] * kernel(supportVectors[i], inputs);
            }
            return sum >= 0 ? 1 : -1;
        }
    }

    // 示例程序
    public class SVMExample
    {
        public SVMExample()
        {
            // 示例数据
            double[][] inputs = new double[][]
        {
            new double[] { 1.0, 2.0 },
            new double[] { 1.1, 2.1 },
            new double[] { 1.2, 2.2 },
            new double[] { 1.3, 2.3 },
            new double[] { 10.0, 10.0 },
            new double[] { 10.1, 10.1 }
        };

            int[] targets = { -1, -1, -1, -1, 1, 1 }; // 目标类别

            // 创建模型（使用高斯核）
            SVM model = new SVM(learningRate: 0.01, lambda: 0.01, maxIterations: 1000, kernel: (x1, x2) =>
            {
                double gamma = 1.0;
                double sum = 0.0;
                for (int i = 0; i < x1.Length; i++)
                {
                    sum += Math.Pow(x1[i] - x2[i], 2);
                }
                return Math.Exp(-gamma * sum);
            });

            // 训练模型
            model.Train(inputs, targets);

            // 预测
            double[] testInput = { 1.0, 2.0 };
            int predictedClass = model.Predict(testInput);

            System.Console.WriteLine("预测类别: " + predictedClass);
        }
    }
}
